#include "cp_info.h"
#include "util.h"
#include "types.h"
cp_info* cp_info::create(char* &buffer){
	char tag_tmp;
	tag_tmp = getU1(buffer); buffer++;
	cp_info *info = NULL;
	/*cout<<"cp_info::tag::"<<(int)tag_tmp;*/
	switch(tag_tmp){
			case CONSTANT_Class:
				info = new constant_class_info();
				((constant_class_info*)info)->name_index = getU2(buffer);buffer += 2;
				/*cout<<"name_index::"<<((constant_class_info*)info)->name_index<<'\n';*/
				break;
			case CONSTANT_Fieldref:
				info = new constant_fieldref_info();
				((constant_fieldref_info*)info)->class_index = getU2(buffer);buffer += 2;
				((constant_fieldref_info*)info)->name_and_type_index = getU2(buffer);buffer += 2;
				break;
			case CONSTANT_Methodref:
				info = new constant_methodref_info();
				((constant_methodref_info*)info)->class_index = getU2(buffer);buffer += 2;
				((constant_methodref_info*)info)->name_and_type_index = getU2(buffer); buffer += 2;
				/*cout<<"class_index::"<<((constant_methodref_info*)info)->class_index<<"name_and_type_index::"<<((constant_methodref_info*)info)->name_and_type_index<<'\n';*/
				break;
			case CONSTANT_InterfaceMethodref:
				info = new constant_interfacemethodref_info();
				((constant_interfacemethodref_info*)info)->class_index = getU2(buffer);buffer += 2;
				((constant_interfacemethodref_info*)info)->name_and_type_index = getU2(buffer);buffer += 2;
				break;
			case CONSTANT_String:
				info = new constant_string_info();
				((constant_string_info*)info)->string_index = getU2(buffer);buffer += 2;
				break;
			case CONSTANT_Integer:
				info = new constant_integer_info();
				((constant_integer_info*)info)->bytes = getU4(buffer);buffer += 4;
				break;
			case CONSTANT_Float:
				info = new constant_float_info();
				((constant_float_info*)info)->bytes = getU4(buffer);buffer += 4;
				break;
			case CONSTANT_Long:
				info = new constant_long_info();
				((constant_long_info*)info)->high_bytes = getU4(buffer);buffer += 4;
				((constant_long_info*)info)->low_bytes = getU4(buffer);buffer += 4;
				break;
			case CONSTANT_Double:
				info = new constant_double_info();
				((constant_double_info*)info)->high_bytes = getU4(buffer);buffer += 4;
				((constant_double_info*)info)->low_bytes = getU4(buffer);buffer += 4;
				break;
			case CONSTANT_NameAndType:
				info = new constant_nameandtype_info();
				((constant_nameandtype_info*)info)->name_index = getU2(buffer);buffer += 2;
				((constant_nameandtype_info*)info)->descriptor_index = getU2(buffer);buffer += 2;
				break;
			case CONSTANT_Utf8:
				info = new constant_utf8_info();
				char c;
				((constant_utf8_info*)info)->length = getU2(buffer);buffer += 2;
				char *pText = new char[((constant_utf8_info*)info)->length ];
				for(int i = 0; i < ((constant_utf8_info*)info)->length ; i++){
					c = getU1(buffer);buffer += 1;      
					pText[i] = c;
				}
				wstring ws = L"";
				wchar_t wc_t;
				int i = 0;
				while(i < ((constant_utf8_info*)info)->length ){
					if((pText[i] & 0x80) == 0){
						wc_t = pText[i];
						i++;
					}else if( i < ((constant_utf8_info*)info)->length  - 1 &&(pText[i] & 0xe0) == 0xc0 && (pText[i+1] & 0xc0) == 0x80){
						wc_t = ((pText[i] & 0x1f) << 6) + (pText[i+1] & 0x3f);
						i += 2;
					}else if(i <  ((constant_utf8_info*)info)->length  - 2 && (pText[i] & 0xf0) == 0xe0 && (pText[i+1] & 0xc0) == 0x80 && (pText[i+2] & 0xc0) == 0x80){
						wc_t = ((pText[i] & 0xf) << 12) + ((pText[i+1] & 0x3f) << 6) + (pText[i+2] & 0x3f);
						i += 3;
					}
					ws += wc_t;
				}
				((constant_utf8_info*)info)->bytes = ws;
				/*wcout<<"utf-8::"<<ws<<'\n';*/
				break;
	}
	info->tag = tag_tmp;
	return info;
}